AWS CLI で describe した JSON の diff でイライラしないために! dictknife normalize を使おう
TL;DR
dictknife diff --normalize
で しあわせになりましょう!pip
でインストールできます!
背景
みなさん、AWS CLI 使ってますか!(挨拶
例えば、既存のある EC2 インスタンスから AMI を取得して別の EC2 インスタンスを作成したりする際など、ふたつの EC2 インスタンス(あるいは他の AWS リソース同士)の差を比較したいという場面は時々あります。
そういうときには AWS CLI で状態を取得、たとえば EC2 の場合であれば describe-instances して、得られた JSON を比較すればいいのですが、、、実際にやってみると、たま(?)に困ったことが起きます。
例えばこんな感じです:
diff -ub i-0000aaaaaaaaaa000.json i-1111bbbbbbbbbb111.json
--- i-0000aaaaaaaaaa000.json 2019-03-xx 14:51:38.000000000 +0900 +++ i-1111bbbbbbbbbb111.json 2019-03-xx 15:03:45.000000000 +0900 (略) "Tags": [ { - "Key": "Name", - "Value": "server-1" + "Key": "Role", + "Value": "webapp" }, { "Key": "Env", "Value": "Prod" }, { - "Key": "Role", - "Value": "webapp" + "Key": "Name", + "Value": "server-2" }, { "Key": "BillingGroup", (略)
この!
差分が 1 箇所なのか 2 箇所なのかびみょうに分かりづらい感じ、伝わりますでしょうか!!
こちらとしては InstanceId
とか PrivateIpAddress
とか、あるいは LaunchTime
などの出て当然の差分、さらにはパラメータ指定ミスなどの 出て欲しくないのに出てしまった差分が無いか が見たい(むしろ本命はこちら)のであって、こういった「実際は差が無いのに差分として表示されるもの」はノイズでしかない、出て欲しくないわけです。
ところが AWS CLI にて describe した結果の JSON では、このような差分が往々にして出力されてしまいます。 Tags の他にも SecurityGroups などもそうですね。。 jq
の --sort-keys (-S)
オプションはキーに対してしか効果がなく、配列まではソートしてくれないためここでは使えません。
では他に何かないか。。。と探して、 id:podhmo 氏が公開されている dictknife にたどり着いたためご紹介します。
dictknife のマニュアルは下記で公開されていますが、すこし前のバージョンしかないようです。
インストール後は --help
でオプションを確認できます。
$ dictknife diff --help usage: dictknife diff [-h] [--normalize] [--verbose] [--n N] [--skip-empty] [-i {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}] [-o {diff,dict,md,tsv,jsonpatch}] [-S] left right diff dict positional arguments: left right optional arguments: -h, --help show this help message and exit --normalize --verbose --n N --skip-empty -i {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}, --input-format {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet} -o {diff,dict,md,tsv,jsonpatch}, --output-format {diff,dict,md,tsv,jsonpatch} -S, --sort-keys
使い方
インストール
pip
で導入できます。
pip install dictknife
差分比較
diff
と使い方はあまりかわりません。 --normalize
オプションを付けて実行するだけです。出力は diff (unified) 形式( diff -u
)固定になります。
dictknife diff --normalize i-0000aaaaaaaaaa000.json i-1111bbbbbbbbbb111.json
前後の行数を広げたい・狭めたいときには --n NN
オプションをつけます。 -n
ではなく -
はふたつですのでお気をつけください。
dictknife diff --normalize --n 10 i-0000aaaaaaaaaa000.json i-1111bbbbbbbbbb111.json
例えば先ほどのサンプル部分は、下記のような感じになります:
(略) { "Key": "BillingGroup", "Value": "Team1" }, { "Key": "Env", "Value": "Prod" }, { "Key": "Name", - "Value": "server-1" + "Value": "server-2" }, { "Key": "Role", "Value": "webapp" } ], (略)
Key
部分がいい感じにソートされてますね!
なお、dictknife も jq と同じく --sort-keys (-S)
オプションが使えます。 AWS CLI の出力はキー順が概ね一定でそんなに困ったことはないですが、もし必要なら指定しましょう。
YAML入力
dictknife は YAML 形式もそのまま入力できるため、YAMLの比較も可能です。
dictknife diff --normalize i-0000aaaaaaaaaa000.yml i-1111bbbbbbbbbb111.yml
ただしその場合でも、内部では JSON に変換して比較が行われるのか、JSON での差分出力になります。
ちなみに
dictknife の出力はシンプルなので、colordiff
や highlight
でいい感じに色づけできます。個人的には colordiff
が単機能で好みですが、highlight
は高機能で HTML 出力まで出来てしまうので、必要に応じて使い分けるとよいかと思います。
brew install colordiff brew install highlight
dictknife diff --normalize a.json b.json | colordiff dictknife diff --normalize a.json b.json | highlight -S diff -O ansi
colordiff
の出力としてはこんな感じです:
なお「 armyknife of handling dict object 」と謳われているとおり、dictknife には他にも便利そうな機能が備わっています。正直なところ自分は使い込むところまでいっていないため、まだその便利さに気付けていませんが、もし JSON を扱う上で困ったことがおありなら、ドキュメントやヘルプを参照してみてください。
まとめ
dictknife をご紹介しました。AWS CLI を使う上で長年面倒に思っていた仕様なのですが、解決策は探せばあるものなのですね。。。
便利なツールを公開してくださっている podhmo 氏に感謝しつつ、みなさんも是非使ってみて下さい。